package com.ling.pl.security.service;

import com.ling.pl.core.cache.ApplicationCache;
import com.ling.pl.core.commons.exception.AccessDeniedException;
import com.ling.pl.core.commons.utils.SpringUtil;
import com.ling.pl.core.dao.IDao;
import com.ling.pl.security.model.DefaultUrl;
import com.ling.pl.security.model.DefaultUser;
import com.ling.pl.security.model.RoleResource;
import com.ling.pl.security.model.UrlComponent;
import com.ling.pl.security.utils.SecurityUtils;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;

import java.util.*;

/**
 * @author bo.wang
 */
@Component(DefaultUrlService.BEAN_ID)
public class DefaultUrlService extends BaseDefaultUrlService {
    public static final String URL_FOR_NAVI_CACHE_KEY = "url_for_navi_cache_key_";
    @Autowired
    @Qualifier(ApplicationCache.BEAN_ID)
    private ApplicationCache applicationCache;

    public ApplicationCache getApplicationCache() {
        return applicationCache;
    }

    public void setApplicationCache(ApplicationCache applicationCache) {
        this.applicationCache = applicationCache;
    }

    public List<DefaultUrl> loadUrlsByRoleId(String roleId) {
        return defaultUrlDao.loadUrlsByRoleId(roleId);
    }

    public List<UrlComponent> loadComponentUrlsByRoleId(final String roleId) {
        return defaultUrlDao.loadComponentUrlsByRoleId(roleId);
    }

    public List<DefaultUrl> loadUrlsByParentId(String parentId) {
        return defaultUrlDao.loadUrlsByParentId(parentId);
    }


    public IDao getDao() {
        return defaultUrlDao;
    }


    public List<UrlComponent> loadUrlsByUrlIdAndroleId(String urlId,
                                                       String roleId) {
        return defaultUrlDao.loadUrlsByUrlIdAndroleId(urlId, roleId);
    }


    public void saveRoleUrls(String roleId, Collection<String> ids) {
        List<RoleResource> roleResources = defaultUrlDao.loadRoleResourceByRoleId(roleId);
        defaultUrlDao.removeAll(roleResources);
        for (String urlId : ids) {
            RoleResource rr = new RoleResource();
            rr.setId(UUID.randomUUID().toString());
            rr.setRoleId(roleId);
            rr.setUrlId(urlId);
            defaultUrlDao.save(rr);
        }

    }

    public Integer loadChildNumByParentId(String parentId) {
        return defaultUrlDao.loadChildNumByParentId(parentId);
    }

    public Collection<DefaultUrl> loadMeunUrlsFromCache(String parentId, String companyId, String userName) {
        companyId = getCompanyIdByUserName(companyId, userName);
        List<DefaultUrl> cacheUrls = (List<DefaultUrl>) this.applicationCache.getCacheObject(URL_FOR_NAVI_CACHE_KEY);
        if (cacheUrls == null) {
            cacheNavigatorUrls();
            cacheUrls = (List<DefaultUrl>) this.applicationCache.getCacheObject(URL_FOR_NAVI_CACHE_KEY);
        }
        Collection<DefaultUrl> urls = getCacheUrls(cacheUrls, companyId, parentId);
        Collection<DefaultUrl> result = new ArrayList<DefaultUrl>();
        authorityCheck(urls, userName, result);
        return result;
    }

    @SuppressWarnings("unchecked")
    public Collection<DefaultUrl> loadMeunUrlsFromCache(String parentId, String userName) {
        return loadMeunUrlsFromCache(parentId, null, userName);
    }

    public Collection<DefaultUrl> loadContainChildMeunUrlsFromCache(String parentId, String userName) {
        return loadContainChildMeunUrlsFromCache(parentId, null, userName);
    }

    public Collection<DefaultUrl> loadContainChildMeunUrlsFromCache(String parentId, String companyId, String userName) {
        companyId = getCompanyIdByUserName(companyId, userName);
        Collection<DefaultUrl> result = this.loadMeunUrlsFromCache(parentId, companyId, userName);
        this.loadContainChildMeunUrls(result, parentId, companyId, userName);
        return result;
    }

    private String getCompanyIdByUserName(String companyId, String userName) {
        if (companyId == null) {
            DefaultUserService userService = SpringUtil.getBean(DefaultUserService.BEAN_ID);
            DefaultUser user = userService.loadUserByUsername(userName);
            if (user == null) {
                throw new AccessDeniedException("错误的用户名");
            }
            companyId = user.getCompanyId();
        }
        return companyId;
    }

    private void authorityCheck(Collection<DefaultUrl> urls, String userName, Collection<DefaultUrl> result) {
        DefaultUserService userService = SpringUtil.getBean(DefaultUserService.BEAN_ID);
        DefaultUser user = userService.loadUserByUsername(userName);
        if (user == null) {
            throw new AccessDeniedException("错误的用户名");
        }
        for (DefaultUrl url : urls) {
            String targetUrl = url.getUrl();
            List<DefaultUrl> children = url.getChildren();
            int childrenCount = 0;
            if (children != null) {
                childrenCount = children.size();
            }
            if (childrenCount == 0 && StringUtils.isEmpty(targetUrl)) {
                continue;
            }
            if (StringUtils.isEmpty(targetUrl)) {
                targetUrl = url.getName();
            }
            try {
//				System.out.println(targetUrl);
                SecurityUtils.checkUrl(userName, targetUrl);
                DefaultUrl newUrl = buildNewUrl(url);
                result.add(newUrl);
                if (children != null) {
                    List<DefaultUrl> childrenUrls = new ArrayList<DefaultUrl>();
                    newUrl.setChildren(childrenUrls);
                    authorityCheck(children, userName, childrenUrls);
                }
            } catch (Exception ex) {
            }
        }
    }

    private void loadContainChildMeunUrls(Collection<DefaultUrl> result, String parentId, String companyId, String userName) {
        for (DefaultUrl url : result) {
            List<DefaultUrl> childList = new ArrayList<DefaultUrl>();
            childList.addAll(this.loadMeunUrlsFromCache(url.getId(), companyId, userName));
            url.setChildren(childList);
            this.loadContainChildMeunUrls(childList, url.getId(), companyId, userName);
        }
    }

    private int fetchChildrenCount(List<DefaultUrl> cacheUrls, String parentId, String companyId) {
//		int count = urlService.loadChildNumByParentId(parentId);
        return this.getCacheUrls(cacheUrls, companyId, parentId).size();
    }

    private List<DefaultUrl> getCacheUrls(List<DefaultUrl> urls, String companyId, String parentId) {
        List<DefaultUrl> resultUrls = new ArrayList<DefaultUrl>();
        this.buildCacheUrls(urls, resultUrls, companyId, parentId);
        return resultUrls;
    }

    private void buildCacheUrls(List<DefaultUrl> urls, List<DefaultUrl> resultUrls, String companyId, String parentId) {
        for (DefaultUrl url : urls) {
            if (url.getChildren() != null && url.getChildren().size() > 0) {
                url.setHasChild(true);
            } else {
                url.setHasChild(false);
            }
            if (StringUtils.isEmpty(parentId)) {
                if (StringUtils.isEmpty(url.getParentId()) && url.getCompanyId() != null && url.getCompanyId().equals(companyId)) {
                    resultUrls.add(url);
                }
            } else {
                if (StringUtils.isNotEmpty(url.getParentId()) && url.getParentId().equals(parentId)) {
                    resultUrls.add(url);
                }
            }
            if (url.getChildren() != null) {
                this.buildCacheUrls(url.getChildren(), resultUrls, companyId, parentId);
            }
        }
    }

    public void cacheNavigatorUrls() {
        Collection<DefaultUrl> urls = loadUrls();
        this.applicationCache.putCacheObject(URL_FOR_NAVI_CACHE_KEY, urls);
    }

    private Collection<DefaultUrl> loadUrls() {
        List<DefaultUrl> allurls = getAllDefaultUrls();
        Map<String, Collection<DefaultUrl>> subordinateRelations = new HashMap<String, Collection<DefaultUrl>>();
        for (DefaultUrl url : allurls) {
            //根据上級ID把下属的机构都归在一个集合下
            if (subordinateRelations.keySet().contains(url.getParentId())) {
                Collection<DefaultUrl> subordinates = subordinateRelations.get(url.getParentId());
                subordinates.add(url);
            } else {
                Collection<DefaultUrl> subordinates = new ArrayList<DefaultUrl>();
                subordinates.add(url);
                subordinateRelations.put(url.getParentId(), subordinates);
            }
        }
        //根据顶层节点组件树
        Collection<DefaultUrl> urls = subordinateRelations.get(null);
        for (DefaultUrl parent : urls) {
            assembleTree(parent, subordinateRelations);
        }
		/* 
		 //改变方式为一次加载,再组合
		urls= loadUrlsByParentId(parentId);
		for(DefaultUrl url:urls){
			url.setChildren(this.loadUrls(url.getId()));
		}*/
        return urls;
    }

    protected void assembleTree(DefaultUrl superior, Map<String, Collection<DefaultUrl>> subordinateRelations) {
        String superiorId = superior.getId();
        superior.setChildren(new ArrayList());
        Collection<DefaultUrl> subordinates = subordinateRelations.get(superiorId);
        if (subordinates == null || subordinates.isEmpty()) {
            return;
        }
        for (DefaultUrl subordinate : subordinates) {
            superior.getChildren().add(subordinate);
            subordinate.setParent(superior);
            assembleTree(subordinate, subordinateRelations);
        }
    }

    private List<DefaultUrl> getAllDefaultUrls() {
        return defaultUrlDao.loadAllUrls();
    }


    private DefaultUrl buildNewUrl(DefaultUrl oldUrl) {
        DefaultUrl url = new DefaultUrl();
        url.setId(oldUrl.getId());
        url.setName(oldUrl.getName());
        url.setDesc(oldUrl.getDesc());
        url.setUrl(oldUrl.getUrl());
        url.setIcon(oldUrl.getIcon());
        url.setParentId(oldUrl.getParentId());
        url.setCompanyId(oldUrl.getCompanyId());
        return url;
    }
}

